
#include "cameraManagement.h"
using namespace cv;
using namespace std;
/*
 * @brief: 打开相机，如果打开成功则初始化参数pFrameBuf, nBuffSize, stInfo
 * @return: 如果打开成功，返回cameraHandle, 否则返回nullptr
 */
void* openCamera(unsigned char* &pFrameBuf, int& nBuffSize, MV_FRAME_OUT_INFO_EX& stInfo, const double expectedFrameRate, const int exposureTime,
                 const int imgHeight, const int imgWidth)
{
    // init camera
    void* cameraHandle = nullptr; // 初始化相机句柄
    int nRet; //相机运行成功参数

    // 枚举设备
    MV_CC_DEVICE_INFO_LIST stDeviceList;
    memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));

    nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
    if (MV_OK != nRet)
    {
        printf("MV_CC_EnumDevices fail! nRet [%x]\n", nRet);
        return nullptr;
    }
    unsigned int nIndex = 0;
    if (stDeviceList.nDeviceNum > 0)
    {
        for (int i = 0; i < stDeviceList.nDeviceNum; i++)
        {
            //printf("[device %d]:\n", i);
            MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];
            if (NULL == pDeviceInfo)
            {
                break;
            }
            //PrintDeviceInfo(pDeviceInfo);
        }
    }
    else
    {
        printf("Find No Devices!\n");
        return nullptr;
    }

    //scanf("%d", &nIndex);

    // 选择设备并创建句柄
    nRet = MV_CC_CreateHandle(&cameraHandle, stDeviceList.pDeviceInfo[nIndex]);
    if (MV_OK != nRet)
    {
        printf("MV_CC_CreateHandle fail! nRet [%x]\n", nRet);
        return nullptr;
    }

    // 打开设备
    // open device
    nRet = MV_CC_OpenDevice(cameraHandle);
    if (MV_OK != nRet)
    {
        printf("MV_CC_OpenDevice fail! nRet [%x]\n", nRet);
        return nullptr;
    }
    nRet = MV_CC_SetFloatValue(cameraHandle, "ExposureTime", default_exposure_time); // TODO
    if (MV_OK != nRet)
    {
        printf("MV_CC_SetFloatValue ExposureTime fail! nRet [%x]\n", nRet);
    }

    // MV_CC_SetAcquisitionLineRate()
    nRet = MV_CC_SetAcquisitionMode(cameraHandle, 2);
    if (MV_OK != nRet)
    {
        printf("MV_CC_SetAcquisitionMode fail! nRet [%x]\n", nRet);
    }
    nRet = MV_CC_SetImageNodeNum(cameraHandle, 1);
    if (MV_OK != nRet)
    {
        printf("MV_CC_SetImageNodeNum fail! nRet [%x]\n", nRet);
    }

    //Set Frame Rate & exposure Time
    nRet = MV_CC_SetExposureTime(cameraHandle, exposureTime);
    if(MV_OK != nRet)
    {
        printf("MV_CC_SetExposureTime fail! nRet [%x]\n", nRet);
    }

    nRet = MV_CC_SetFrameRate(cameraHandle, expectedFrameRate);
    if(MV_OK != nRet)
    {
        printf("MV_CC_SetExposureTime fail! nRet [%x]\n", nRet);
    }

    nRet = MV_CC_SetGain(cameraHandle, 6.0);
    if(MV_OK != nRet)
    {
        printf("MV_CC_SetGain fail! nRet [%x]\n", nRet);
    }

    uint Decimation = 1;
    nRet = MV_CC_SetEnumValue(cameraHandle, "DecimationHorizontal",Decimation);
    if(MV_OK != nRet)
    {
        printf("MV_CC_SetEnumValue DecimationHorizontal fail! nRet [%x]\n", nRet);
    }

    nRet = MV_CC_SetEnumValue(cameraHandle, "DecimationVertical",Decimation);
    if(MV_OK != nRet)
    {
        printf("MV_CC_SetEnumValue DecimationVertical fail! nRet [%x]\n", nRet);
    }


    
    nRet = MV_CC_SetIntValueEx(cameraHandle, "OffsetX", 0);
    if(MV_OK != nRet)
    {
        printf("MV_CC_SetIntValueEx OffsetX fail! nRet [%x]\n", nRet);
    }

    nRet = MV_CC_SetIntValueEx(cameraHandle, "OffsetY", 0);
    if(MV_OK != nRet)
    {
        printf("MV_CC_SetIntValueEx OffsetY  fail! nRet [%x]\n", nRet);
    }



    //Print frame rate and exposureTime
    MVCC_FLOATVALUE* fv = (MVCC_FLOATVALUE*)malloc(sizeof(MVCC_FLOATVALUE));
    nRet = MV_CC_GetFrameRate(cameraHandle, fv);
    if(MV_OK != nRet)
        printf("MV_CC_GetFrameRate fail! nRet [%x]\n", nRet);
    printf("Current frame rate: %lf\n", fv->fCurValue);

    nRet = MV_CC_GetExposureTime(cameraHandle, fv);
    if(MV_OK != nRet)
        printf("MV_CC_GetExposureTime fail! nRet [%x]\n", nRet);
    printf("Current exposure time: %lf\n", fv->fCurValue);

    //Set imgHeight x imgWidth
    nRet = MV_CC_SetHeight(cameraHandle, imgHeight);
    if(MV_OK != nRet)
        printf("MV_CC_SetHeight fail! nRet [%x]\n", nRet);
    nRet = MV_CC_SetWidth(cameraHandle, imgWidth);
    if(MV_OK != nRet)
        printf("MV_CC_SetWidth fail! nRet [%x]\n", nRet);

    MVCC_INTVALUE* intv = (MVCC_INTVALUE*)malloc(sizeof(MVCC_INTVALUE));
    nRet = MV_CC_GetHeight(cameraHandle, intv);
    if(MV_OK != nRet)
        printf("MV_CC_GetHeight fail! nRet [%x]\n", nRet);
    int nHeight = intv->nCurValue;
    nRet = MV_CC_GetWidth(cameraHandle, intv);
    if(MV_OK != nRet)
        printf("MV_CC_GetWidth fail! nRet [%x]\n", nRet);
    int nWidth = intv->nCurValue;
    printf("Current image height x width: %d x %d \n", nHeight, nWidth);

    //Set Image Pixel Format
    nRet = MV_CC_SetPixelFormat(cameraHandle, PixelType_Gvsp_BayerRG8);
    if(MV_OK != nRet)
        printf(" MV_CC_SetPixelFormat to PixelType_Gvsp_BayerRG8 fail! nRet [%x]\n", nRet);

    // 开始取流
    // start grab image
    nRet = MV_CC_StartGrabbing(cameraHandle);
    if (MV_OK != nRet)
    {
        printf("MV_CC_StartGrabbing fail! nRet [%x]\n", nRet);
        return nullptr;
    }

    if(cameraHandle == nullptr)
    {
        printf("[Error] Camera initialization failed!\n ");
        return nullptr;
    }
    else
        printf("Camera initialization succeeds.\n");

    MVCC_INTVALUE stIntvalue = {0};
    nRet = MV_CC_GetIntValue(cameraHandle, "PayloadSize", &stIntvalue);
    if (nRet != MV_OK)
    {
        printf("[Error] Get PayloadSize failed! nRet [%x]\n", nRet);
        cameraExit(cameraHandle);
        return nullptr;
    }

    nBuffSize = MAX_IMAGE_DATA_SIZE;
    pFrameBuf = (unsigned char*)malloc(nBuffSize);
    memset(&stInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));

    return cameraHandle;
}

/*
 * @brief: 从相机中读取一张图片
 * @return: 如果读取成功，返回Mat, 否则返回nullptr
 */
Mat* readFromCamera(void* cameraHandle, Mat& output, unsigned char* pFrameBuf, const int nBuffSize, MV_FRAME_OUT_INFO_EX& stInfo)
{
    auto nRet = MV_CC_GetImageForBGR(cameraHandle, pFrameBuf, nBuffSize, &stInfo, 1000);
    if( nRet != 0 )
    {
        cout << "[Error]: GetImageForRGB:" << setbase(16) << nRet << endl;
        return nullptr;
    } else {
        auto width_fig = stInfo.nWidth;
        auto height_fig = stInfo.nHeight;
        if (stInfo.enPixelType == PixelType_Gvsp_BGR8_Packed) {
            Mat pImg(height_fig, width_fig, CV_8UC3, pFrameBuf);
            output = pImg;
            return &output;
        }
    }
}

/**
 * @author      Seafood
 * @name        PrintDeviceInfo
 * @return      bool
 * @function    打印摄像头信息
 * @para        pstMVDevInfo
 * */
bool PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo)
{
    //查看是否有devInfolist
    if (nullptr == pstMVDevInfo)
    {
        printf("%s\n" , "The Pointer of pstMVDevInfoList is NULL!");
        return false;
    }
    //网络摄像头
    if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE)
    {
		// 打印当前相机ip和用户自定义名字
		// print current ip and user defined name
        printf("%s %x\n" , "nCurrentIp:" , pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp);                 
        printf("%s %s\n\n" , "chUserDefinedName:" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);   
    }
    //USB摄像头
    else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE)
    {
        printf("UserDefinedName:%s\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);
    }
    //其他
    else
    {
        printf("Not support.\n");
    }
    return true;
}

// void paraInit()
// {
//     //一帧数据大小
//     nBuffSize = MAX_IMAGE_DATA_SIZE;
//     nRet  = -1 ;                    //相机状态代码
//     handle  = NULL ;              //相机用参数  
//     pFrameBuf = NULL;            //相机位置
//     if(mcu_data.env_light > 0 && mcu_data.env_light < 20){
//         fExposureTime=1000;
//     }
//     else if(mcu_data.env_light >= 20 && mcu_data.env_light < 40){
//         fExposureTime=3000;
//     }
//     else if(mcu_data.env_light >= 40 && mcu_data.env_light < 60){
//         fExposureTime=5000;
//     }
//     else if(mcu_data.env_light >= 60 && mcu_data.env_light < 80){
//         fExposureTime=7000;
//     }
//     else{
//         fExposureTime=EXPO_CLASS_5;
//     }
// }

/**
 * @author      Seafood
 * @name        cameraExit
 * @return      int
 * @function    摄像头退出
 * @para        None
 * */
int cameraExit(void* cameraHandle)
{
    // 停止取流
	// end grab image
    int nRet = MV_CC_StopGrabbing(cameraHandle);
    if (MV_OK != nRet)
    {
        printf("MV_CC_StopGrabbing fail! nRet [%x]\n", nRet);
        return -1;
    }

    // 关闭设备
	// close device
    nRet = MV_CC_CloseDevice(cameraHandle);
    if (MV_OK != nRet)
    {
        printf("MV_CC_CloseDevice fail! nRet [%x]\n", nRet);
        return -1;
    }

    // 销毁句柄
	// destroy cameraHandle
    nRet = MV_CC_DestroyHandle(cameraHandle);
    if (MV_OK != nRet)
    {
        printf("MV_CC_DestroyHandle fail! nRet [%x]\n", nRet);
        return -1;
    }
	
	printf("exit\n");
    return 1;
}
